home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 17 code / PwrPC Debugging / CrashOMatic / CrashOMatic.c next >
Encoding:
C/C++ Source or Header  |  1993-12-01  |  10.4 KB  |  382 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple Sample Application
  6. #
  7. #    CrashOMatic
  8. #
  9. #    CrashOMatic.c    -    C Source (main segment)
  10. #
  11. #    Copyright © 1989-93 Apple Computer, Inc.
  12. #
  13. #
  14. #    This is the sample app modified for CrashOMatic functionality
  15. #    Written by Brian Topping
  16. ------------------------------------------------------------------------------*/
  17.  
  18.  
  19.  
  20. #pragma segment Main
  21.  
  22. #include <Values.h>
  23. #include <Types.h>
  24. #include <Resources.h>
  25. #include <QuickDraw.h>
  26. #include <Fonts.h>
  27. #include <Events.h>
  28. #include <Windows.h>
  29. #include <Menus.h>
  30. #include <TextEdit.h>
  31. #include <Dialogs.h>
  32. #include <Desk.h>
  33. #include <ToolUtils.h>
  34. #include <Memory.h>
  35. #include <SegLoad.h>
  36. #include <Files.h>
  37. #include <OSUtils.h>
  38. #include <OSEvents.h>
  39. #include <DiskInit.h>
  40. #include <Packages.h>
  41. #include <Traps.h>
  42. //#include <MacHeaders>
  43. #include <MachineExceptions.h>
  44. #include <setjmp.h>
  45. #include "CrashOMatic.h"
  46.  
  47. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  48. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  49. #define TopLeft(aRect)    (* (Point *) &(aRect).top)
  50. #define BotRight(aRect)    (* (Point *) &(aRect).bottom)
  51.  
  52. QDGlobals        qd;
  53. static jmp_buf    *curJmpBuf;
  54. Boolean            gUseExceptionHandlers;
  55.  
  56. extern void _DataInit();
  57.  
  58. ////////////////////////////////////////////////////////////////////////////////
  59. // CrashOMatic Specific
  60. ////////////////////////////////////////////////////////////////////////////////
  61.  
  62. // EXCEPTION HANDLER NOTES:
  63. // These are the same exception handlers that the memory manager uses and are
  64. // re-entrant so long as they are not pre-empted.  They are useable as you
  65. // see them in your own application. The trick is to save the longjmp buffer on
  66. // the stack, and save the address of it in a global.  When we get an
  67. // exception, we use the global to find the correct state to resume, and longjmp
  68. // through it with a non-zero error value.  This causes the conditional around our
  69. // setjmp to go to the error handling code.
  70. OSErr HeapExceptionHandler(ExceptionInformation *theException)
  71. {
  72.     // just get back to where we started
  73.     // if we cared what the exception was, we could pass it
  74.     // in place of our favorite constant, letting the app know a bit more...
  75.     longjmp(*curJmpBuf,69);
  76. }
  77.  
  78. void doExceptionProtected(short selection)
  79. {
  80. OSErr                theErr;
  81. jmp_buf                localJump, *oldJump;
  82. ExceptionHandler    oldHandler;
  83. long                illegalAddr, temp;
  84.  
  85.     // set up our illegal address
  86.     illegalAddr = 0xDEADBEEF;
  87.     
  88.     // set up exception buffer addresses
  89.     oldJump = curJmpBuf;
  90.     curJmpBuf = &localJump;
  91.     
  92.     oldHandler = InstallExceptionHandler((ExceptionHandler)HeapExceptionHandler);
  93.     if (theErr = setjmp(localJump)) {
  94.         // If we wanted to do something here with the exception, we could
  95.         // all we really want to do though is have a alternate that doesn't loop
  96.         }
  97.     else {
  98.         // here is where we do the dirty deed
  99.         switch (selection) {
  100.             case iIllegal:
  101.                 (*((ProcPtr)0))();
  102.                 break;
  103.             case iBusError:
  104.                 temp = *((long *)illegalAddr);
  105.                 break;
  106.             }
  107.         }
  108.  
  109.     InstallExceptionHandler(oldHandler);
  110.     curJmpBuf = oldJump;
  111. }
  112.  
  113. void doWithoutProtection(short selection)
  114. {
  115. long                illegalAddr, temp;
  116.  
  117.     // set up our illegal address
  118.     illegalAddr = 0xDEADBEEF;
  119.     
  120.     // here is where we do the dirty deed
  121.     switch (selection) {
  122.         case iIllegal:
  123.             (*((ProcPtr)0))();
  124.             break;
  125.         case iBusError:
  126.             temp = *((long *)illegalAddr);
  127.             break;
  128.         }
  129. }
  130.  
  131. ////////////////////////////////////////////////////////////////////////////////
  132. // DTS Sample shell
  133. ////////////////////////////////////////////////////////////////////////////////
  134. main()
  135. {
  136.     UnloadSeg((Ptr) _DataInit);        /* note that _DataInit must not be in Main! */
  137.  
  138.     MaxApplZone();                    /* expand the heap so code segments load at the top */
  139.  
  140.     Initialize();                    /* initialize the program */
  141.     UnloadSeg((Ptr) Initialize);    /* note that Initialize must not be in Main! */
  142.  
  143.     EventLoop();                    /* call the main event loop */
  144. }
  145.  
  146.  
  147. void EventLoop()
  148. {
  149.     RgnHandle    cursorRgn;
  150.     Boolean        gotEvent;
  151.     EventRecord    event;
  152.     Point        mouse;
  153.  
  154.     cursorRgn = NewRgn();            /* we’ll pass WNE an empty region the 1st time thru */
  155.     do {
  156.         GetGlobalMouse(&mouse);
  157.         gotEvent = WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn);
  158.  
  159.         if ( gotEvent ) {
  160.             DoEvent(&event);
  161.         }
  162.     } while ( true );    /* loop forever; we quit via ExitToShell */
  163. } /*EventLoop*/
  164.  
  165.  
  166. /* Do the right thing for an event. Determine what kind of event it is, and call
  167.  the appropriate routines. */
  168.  
  169. void DoEvent(EventRecord *event)
  170. {
  171.     short        part, err;
  172.     WindowPtr    window;
  173.     Boolean        hit;
  174.     char        key;
  175.     Point        aPoint;
  176.  
  177.     switch ( event->what ) {
  178.         case mouseDown:
  179.             part = FindWindow(event->where, &window);
  180.             switch ( part ) {
  181.                 case inMenuBar:                /* process a mouse menu command (if any) */
  182.                     DoMenuCommand(MenuSelect(event->where));
  183.                     break;
  184.                 case inSysWindow:            /* let the system handle the mouseDown */
  185.                     SystemClick(event, window);
  186.                     break;
  187.                 case inDrag:                /* pass screenBits.bounds to get all gDevices */
  188.                     DragWindow(window, event->where, &qd.screenBits.bounds);
  189.                     break;
  190.                 case inGrow:
  191.                     break;
  192.                 case inZoomIn:
  193.                 case inZoomOut:
  194.                     hit = TrackBox(window, event->where, part);
  195.                     if ( hit ) {
  196.                         SetPort(window);                /* the window must be the current port... */
  197.                         EraseRect(&window->portRect);    /* because of a bug in ZoomWindow */
  198.                         ZoomWindow(window, part, true);    /* note that we invalidate and erase... */
  199.                         InvalRect(&window->portRect);    /* to make things look better on-screen */
  200.                     }
  201.                     break;
  202.             }
  203.             break;
  204.         case keyDown:
  205.         case autoKey:                        /* check for menukey equivalents */
  206.             key = event->message & charCodeMask;
  207.             if ( event->modifiers & cmdKey )            /* Command key down */
  208.                 if ( event->what == keyDown ) {
  209.                     DoMenuCommand(MenuKey(key));
  210.                 }
  211.             break;
  212.         case diskEvt:
  213.             if ( HiWord(event->message) != noErr ) {
  214.                 SetPt(&aPoint, kDILeft, kDITop);
  215.                 err = DIBadMount(aPoint, event->message);
  216.             }
  217.             break;
  218.     }
  219. } /*DoEvent*/
  220.  
  221.  
  222.  
  223. void GetGlobalMouse(Point *mouse)
  224. {
  225.     EventRecord    event;
  226.     
  227.     OSEventAvail(kNoEvents, &event);    /* we aren't interested in any events */
  228.     *mouse = event.where;                /* just the mouse position */
  229. } /*GetGlobalMouse*/
  230.  
  231.  
  232. void DoMenuCommand(long menuResult)
  233. {
  234.     short        menuID;                /* the resource ID of the selected menu */
  235.     short        menuItem;            /* the item number of the selected menu */
  236.     short        itemHit;
  237.     Str255        daName;
  238.     short        daRefNum;
  239.     Boolean        handledByDA;
  240.  
  241.     menuID = HiWord(menuResult);    /* use macros for efficiency to... */
  242.     menuItem = LoWord(menuResult);    /* get menu item number and menu number */
  243.     switch ( menuID ) {
  244.         case mApple:
  245.             switch ( menuItem ) {
  246.                 case iAbout:        /* bring up alert for About */
  247.                     itemHit = Alert(rAboutAlert, nil);
  248.                     break;
  249.                 default:            /* all non-About items in this menu are DAs */
  250.                     /* type Str255 is an array in MPW 3 */
  251.                     GetItem(GetMHandle(mApple), menuItem, daName);
  252.                     daRefNum = OpenDeskAcc(daName);
  253.                     break;
  254.             }
  255.             break;
  256.         case mFile:
  257.             switch ( menuItem ) {
  258.                 case iQuit:
  259.                     Terminate();
  260.                     break;
  261.             }
  262.             break;
  263.         case mEdit:                    /* call SystemEdit for DA editing & MultiFinder */
  264.             handledByDA = SystemEdit(menuItem-1);    /* since we don’t do any Editing */
  265.             break;
  266.         case mTest:
  267.             switch ( menuItem ) {
  268.                 case iDebugger:
  269.                     DebugStr("\pWelcome home!");
  270.                     break;
  271.                 case iClobber:
  272.                     *((long *)0) = -1;
  273.                     break;
  274.                 case iIllegal:
  275.                 case iBusError:
  276.                     if (gUseExceptionHandlers)
  277.                         doExceptionProtected(menuItem);
  278.                     else
  279.                         doWithoutProtection(menuItem);                                                    // you really should wear a raincoat!
  280.                     break;
  281.                 case iExceptionHandlers:
  282.                     gUseExceptionHandlers = (gUseExceptionHandlers ? 0:1);
  283.                     CheckItem(GetMenu(mTest),iExceptionHandlers,gUseExceptionHandlers);
  284.                     break;
  285.             }
  286.             break;
  287.     }
  288.     HiliteMenu(0);                    /* unhighlight what MenuSelect (or MenuKey) hilited */
  289. } /*DoMenuCommand*/
  290.  
  291.  
  292. Boolean DoCloseWindow(WindowPtr window)
  293. {
  294.     if ( IsDAWindow(window) )
  295.         CloseDeskAcc(((WindowPeek) window)->windowKind);
  296.     return true;
  297. } /*DoCloseWindow*/
  298.  
  299.  
  300. void Terminate()
  301. {
  302.     WindowPtr    aWindow;
  303.     Boolean        closed;
  304.     
  305.     closed = true;
  306.     do {
  307.         aWindow = FrontWindow();                /* get the current front window */
  308.         if (aWindow != nil)
  309.             closed = DoCloseWindow(aWindow);    /* close this window */    
  310.     }
  311.     while (closed && (aWindow != nil));
  312.     if (closed)
  313.         ExitToShell();                            /* exit if no cancellation */
  314. } /*Terminate*/
  315.  
  316. /* Check to see if a window belongs to a desk accessory. */
  317.  
  318. Boolean IsDAWindow(WindowPtr window)
  319. {
  320.     if ( window == nil )
  321.         return false;
  322.     else    /* DA windows have negative windowKinds */
  323.         return ( ((WindowPeek) window)->windowKind < 0 );
  324. } /*IsDAWindow*/
  325.  
  326.  
  327. void AlertUser()
  328. {
  329.     short        itemHit;
  330.  
  331.     SetCursor(&qd.arrow);
  332.     itemHit = Alert(rUserAlert, nil);
  333.     ExitToShell();
  334. } /* AlertUser */
  335.  
  336. /*    Set up the whole world, including global variables, Toolbox managers,
  337.     and menus. We also create our one application window at this time.
  338.     Since window storage is non-relocateable, how and when to allocate space
  339.     for windows is very important so that heap fragmentation does not occur.
  340.     Because Sample has only one window and it is only disposed when the application
  341.     quits, we will allocate its space here, before anything that might be a locked
  342.     relocatable object gets into the heap. This way, we can force the storage to be
  343.     in the lowest memory available in the heap. Window storage can differ widely
  344.     amongst applications depending on how many windows are created and disposed. */
  345.  
  346. /*    1.01 - The code that used to be part of ForceEnvirons has been moved into
  347.     this module. If an error is detected, instead of merely doing an ExitToShell,
  348.     which leaves the user without much to go on, we call AlertUser, which puts
  349.     up a simple alert that just says an error occurred and then calls ExitToShell.
  350.     Since there is no other cleanup needed at this point if an error is detected,
  351.     this form of error- handling is acceptable. If more sophisticated error recovery
  352.     is needed, an exception mechanism, such as is provided by Signals, can be used. */
  353.  
  354. void Initialize()
  355. {
  356.     Handle        menuBar;
  357.     EventRecord event;
  358.     short        count;
  359.  
  360.     InitGraf((Ptr) &qd.thePort);
  361.     InitFonts();
  362.     InitWindows();
  363.     InitMenus();
  364.     TEInit();
  365.     InitDialogs(nil);
  366.     InitCursor();
  367.     
  368.     gUseExceptionHandlers = false;
  369.     
  370.     for (count = 1; count <= 3; count++)
  371.         EventAvail(everyEvent, &event);
  372.  
  373.     menuBar = GetNewMBar(rMenuBar);            /* read menus into menu bar */
  374.     if ( menuBar == nil ) AlertUser();
  375.     SetMenuBar(menuBar);                    /* install menus */
  376.     DisposHandle(menuBar);
  377.     AddResMenu(GetMHandle(mApple), 'DRVR');    /* add DA names to Apple menu */
  378.     DrawMenuBar();
  379.     
  380. } /*Initialize*/
  381.  
  382.